package com.example.flieswar.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
    /*
     * Java中的游戏面板：JPanel
     * 自定义游戏面板：
     *  	1.写一个类，继承JPanel
     *  	2.写一个构造方法，初始化确定面板的属性
     */
public class GamePanel extends JPanel{
        //定义背景图
        BufferedImage bg;
        //创建英雄机
        Hero hero = new Hero();
        //创建敌机大本营（所有的敌机都放在这里）
//	Ep ep = new Ep(); <>泛型，可指定类型，只能为敌机Ep
        //分数
        int scores = 0;
        //游戏结束的开关
        boolean gameOver; //游戏开始时，默认为false 结束为true

        List<Ep> eps = new ArrayList<Ep>();
        //创建英雄机的弹药库
        List<Fire> frs = new ArrayList<Fire>();

        public static void main(String[] args) {

        }

        /**
         * 开始游戏的方法
         * @param gf
         */
        public void startGameAction(){
            //创建并启动一个线程，控制游戏场景中物体的活动
            //固定格式
            new Thread(){
                public void run() {
                    //写一个死循环，让游戏一直运行
                    while(true) {
                        if(!gameOver) {//游戏没结束时
                            //调用敌机入场的方法
                            epEnter();
                            //调用让敌机移动的方法
                            epMove();
                            //发射子弹
                            shoot();
                            //让子弹移动
                            fireMove();
                            //判断子弹是否打到敌机
                            shootEp();
                            //判断敌机是否击中了英雄机
                            hit();
                        }

                        //每执行一次，休息一会儿
                        //线程休眠，sleep毫秒
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //重绘
                        repaint();
                    }
                }

            }.start();
        }

        /**
         * 检测敌机是否撞到了英雄机
         */
        protected void hit() {
            //遍历敌机
            for(int i = 0;i < eps.size();i++) {
                //获取一个敌机
                Ep ep = eps.get(i);
                //如果敌机被英雄机撞上
                if(ep.hitBy(hero)) {
                    //1.英雄机有主角光环。移除敌机
                    eps.remove(ep);
                    //2.英雄机血量减少
                    hero.hp -- ;
                    //3.增加分数
                    scores += 10;
                    //4.当英雄机的血量减少到0时，游戏结束
                    if(hero.hp <= 0) {
                        //将开关设置为true 游戏结束
                        gameOver = true;
                    }
                }
            }

        }

        /**
         * 检测子弹是否击中敌机
         * 是否所有的敌机都有可能被子弹击中(排除移出屏幕的敌机)
         */
        protected void shootEp() {
            //遍历所有子弹
            for(int i = 0;i < frs.size();i++) {
                Fire fr = frs.get(i);
                //每拿到一颗子弹，就判断这可子弹是否击中敌机
                bang(fr);
            }
        }

        /**
         * 判断一颗子弹是否击中了敌机
         * @param f
         */
        private void bang(Fire fr) {
            //遍历所有敌机
            for(int i = 0;i < eps.size();i++) {
                //获取每一架敌机
                Ep ep = eps.get(i);
                //判断子弹是否击中敌机
                if(ep.shootBy(fr)) {//敌机被子弹击中
                    ep.hp --;
                    if(ep.hp <= 0) {
                        //1.敌机死亡（消失：从敌机大本营中删除）
                        eps.remove(ep);
                        //2.子弹消失：从弹药库中删除
                        frs.remove(fr);
                        //3.增加分数
                        scores += 10;
                    }

                }
            }
        }


        /**
         * 创建并且发射子弹的方法
         */
        int fIndex = 0;//计数器，记录shoot方法执行的次数
        protected void shoot() {
            fIndex ++;
            if(fIndex >= 10) {
                //创建子弹
                Fire fr0 = new Fire(hero.x + 5, hero.y,0);
                //将子弹加入到弹药库中
                frs.add(fr0);

                //创建子弹
                Fire fr1 = new Fire(hero.x + 18, hero.y,1);
                //将子弹加入到弹药库中
                frs.add(fr1);

                //创建子弹
                Fire fr2 = new Fire(hero.x + 31, hero.y,2);
                //将子弹加入到弹药库中
                frs.add(fr2);
                fIndex = 0;
            }

        }


        /**
         * 子弹移动的方法
         */
        protected void fireMove() {
            //遍历所有子弹
            for(int i = 0;i < frs.size();i++) {
                //获取每一个子弹
                Fire fr = frs.get(i);
                //让子弹移动
                fr.move();
            }
        }

        /**
         * 敌机移动的方法
         */
        protected void epMove() {
            //遍历所有敌机
            for(int i = 0;i < eps.size();i++) {
                //获取每一个敌机
                Ep ep = eps.get(i);
                //让敌机移动
                ep.move();
            }
        }

        /**
         * 敌机入场的方法
         * 因为此方法在死循环中调用的，所以该方法一直在重复执行
         * 敌机出现的频率是否太快
         * 执行20次epEnter（）方法，才创建一个敌机，
         */
        int index = 0;//记录方法执行的次数，每执行n次，释放一个敌机
        protected void epEnter() {
            //记录执行的次数
            index ++;
            if(index >= 20) {
                //1.创建敌机
                Ep ep = new Ep();

                //将敌机添加到敌机大本营中
                eps.add(ep);

                index = 0;
            }

        }

        /*
         * 构造器，构造方法：确定面板的特点
         */
        public GamePanel(GameFrame gf){
            //设置背景
            setBackground(Color.pink);

            //初始化图片
            bg = App.getImg("/imgs/intro_3.jpg");

            //使用鼠标监听器（固定格式）
            //1.创建鼠标适配器
            MouseAdapter adapter = new MouseAdapter(){
                //2.确定需要监听的鼠标事件
                //鼠标的事件
                //1.mouseMoved() 	监听鼠标移动事件
                //2.mouseClicked() 	监听鼠标点击事件
                //3.mousePressed() 	监听鼠标按下去的事件
                //4.mouseEntered() 	监听鼠标移入游戏界面事件
                //5.mouseExited() 	监听鼠标移出游戏界面事件
                public void mouseClicked(MouseEvent e) {
                    //点击鼠标时，会执行的代码
                    //如果游戏结束了，点击屏幕会重新开始游戏，要做什么：
                    if(gameOver) {
                        //英雄机的血量，重新创建一个英雄机
                        hero = new Hero();
                        //重置游戏开关
                        gameOver = false;
                        //分数清零
                        scores = 0;
                        //重绘,刷新UI
                        repaint();
                    }
                }
                //鼠标的事件，记录鼠标做的事情
                public void mouseMoved(MouseEvent e) {
                    //当鼠标在游戏界面移动时，会触发的方法
                    //让英雄机跟着鼠标一起移动
                    //让英雄机的横纵坐标等于鼠标的横纵坐标
                    //获取鼠标的横纵坐标
                    int mx = e.getX();//鼠标的横坐标
                    int my = e.getY();//鼠标的纵坐标

                    if(!gameOver) {//游戏没结束时;结束后 英雄机也停止发射子弹
                        //让英雄机移动到鼠标的位置(英雄机的行为，可以再英雄机中定义移动到鼠标的坐标的方法)
                        hero.x = mx;
                        hero.y = my;
                        hero.movetoMouse(mx, my);
                    }
                    //重绘，类似主线程更新UI
                    repaint();
                }
            };

            //3.将适配器加入到监听器中（固定格式）
            addMouseListener(adapter);
            addMouseMotionListener(adapter);

            //4使用键盘监听器（固定格式）
            //4.1创建键盘适配器
            //4.2确定需要监听的键盘事件
            KeyAdapter kd = new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                    //当按下键盘的按键时，会触发的方法
                    //监听键盘的按键
                    //每一个键盘的按键都对应一个数字
                    //获取键盘上的数字
                    int keyCode = e.getKeyCode();
                    if(keyCode == KeyEvent.VK_UP) {//向上移动
                        hero.moveUp();
                    }else if(keyCode == KeyEvent.VK_DOWN){//向下移动
                        hero.moveDown();
                    }else if(keyCode == KeyEvent.VK_LEFT){//向左移动
                        hero.moveLeft();
                    }else if(keyCode == KeyEvent.VK_RIGHT){//向右移动
                        hero.moveRight();
                    }
                    //重绘，将英雄机重绘在新的位置上
                    repaint();
                }
            };
            //4.3将适配器加入到窗体的键盘监听器中
            gf.addKeyListener(kd);
        }

        /*
         * 专用的画图方法
         */
        public void paint(Graphics g) {
            super.paint(g);
            //画图片
            //g.drawImage(图片, 横坐标, 纵坐标,null)
            //横纵坐标是设置图片左上角的坐标
            //画图片时如果不加宽高，画的是原图大小，修改宽高使用如下格式
//		g.drawImage(img, x, y, width, height, null)
            //将背景图画在游戏面板上
            g.drawImage(bg, 0, 0, 512, 768, null);
            //在paint中画图是有顺序的，先画的会被后画的覆盖
            //将英雄机画在游戏面板上
            g.drawImage(hero.img, hero.x, hero.y, hero.w, hero.h, null);
            //将敌机画在游戏面板上
            //遍历并将敌机绘制到游戏面板上
            for(int i = 0;i < eps.size();i++) {
                Ep ep = eps.get(i);
                g.drawImage(ep.img, ep.x, ep.y, ep.w, ep.h, null);

            }

            //将子弹画在游戏面板上
            //遍历并将子弹绘制到游戏面板上
            for(int i = 0;i < frs.size();i++) {
                Fire fr = frs.get(i);
                g.drawImage(fr.img, fr.x, fr.y, fr.w, fr.h, null);

            }

            //画分数
            g.setColor(Color.white);
            g.setFont(new Font("楷体", Font.BOLD, 30));
            g.drawString("分数:" + scores, 10, 30);

            //画英雄机的血量
            for(int i = 0;i < hero.hp;i++) {
                g.drawImage(hero.img, 400 + i * 35, 5, 30, 30, null);
            }

            //游戏结束时，画出gameOver
            if(gameOver) {
                g.setColor(Color.red);
                g.setFont(new Font("楷体", Font.BOLD, 35));
                g.drawString("--------Game Over--------", 20, 300);

                g.setColor(Color.green);
                g.setFont(new Font("楷体", Font.BOLD, 20));
                g.drawString("-----HR 提醒你点击屏幕，重新开始游戏-----", 40, 400);

            }

        }
}
